#include "bsp.h"
#include "mrfi.h"
#include "nwk_types.h"
#include "nwk_api.h"
#include "nwk.h"
#include "bsp_leds.h"
#include "bsp_buttons.h"
#include "RCR.h"

#define RCR_2


static  linkID_t linkID;			// link ID for device
uint8_t zone;
uint8_t message[3] = {0,0,0};		// buffer for both sending and receiving messages					

uint8_t sleepTime=2;				// mem location for CTC requested sleep time

volatile uint8_t secondsSlept = 0;	// global sleep counter
volatile uint8_t gotMessage = 0;	// global flag for received message
volatile uint16_t numSeconds = 0;	// global mem for wait function sleeps

volatile uint8_t direction = OPEN;				// state variable that holds the direction the motor should rotate in
volatile uint8_t newDirection = OPEN;			// state variable that holds the new driection received from CTC
volatile uint8_t stop = FALSE;					// state variable that says when the motor should stop
volatile uint8_t motorState = 1;				// holds the value of the stepper coils

void main(void)
{
	
 	RCRInit();			// Init Registers for RCR Device Settings
 	
  	CTCLink();			// Link to CTC

	while(ALWAYS)		// Loop Through Sleep Transmit Tasks
	{
	 	wait(sleepTime);							// enter low power mode
		
 	 	SMPL_Ioctl(IOCTL_OBJ_RADIO, IOCTL_ACT_RADIO_AWAKE,0);
 	 	SMPL_Ioctl(IOCTL_OBJ_RADIO, IOCTL_ACT_RADIO_RXON, 0);	// turn radio on
 	 
 	 	BSP_TOGGLE_LED1();		// DEBUG
 	 
 	 	sendReq();									// poll CTC for current vent status
 	 												// also gets new sleep time
 	 												
 	 	updateVentPosition();						// move vent baffles if necessary
 	 	
 	 	SMPL_Ioctl(IOCTL_OBJ_RADIO, IOCTL_ACT_RADIO_RXIDLE, 0);	// turn radio off
 	 
 	 	TA1CCR0 = TA1R + SLEEP_PERIOD;				// setup vars for new sleep period
 	 	TA1CCTL0 |= CCIE;
	}
	/*
	WDTCTL = WDTPW + WDTHOLD;              	// Stop WDT for development
  	BSP_Init();
  	TA1CCR0 	= SLEEP_PERIOD;				// Load cap comp register with sleep period
  	TA1CCTL0 	= CCIE;                     // CCR0 interrupt enabled
  	TA1CTL 		= TASSEL_1 + MC_2;          // ACLK, continuous mode
  	
  	P1DIR = 0xFF;
  	P1OUT = 0xFF;
  	
  	
  	while(1);
  	*/
}

void RCRInit()
{
	// auto set device address
	addr_t device;
	
	#ifdef RCR_1
		device.addr[0] = 0x69;
		device.addr[1] = 0x56;
		device.addr[2] = 0x34;
		device.addr[3] = 0x12;
	#elif defined RCR_2
		device.addr[0] = 0x70;
		device.addr[1] = 0x56;
		device.addr[2] = 0x34;
		device.addr[3] = 0x12;
	#endif
	
	SMPL_Ioctl(IOCTL_OBJ_ADDR, IOCTL_ACT_SET, (void*)&device);
	
	
  	WDTCTL = WDTPW + WDTHOLD;              	// Stop WDT for development
  	BSP_Init();								// Init Dev Board
  	SMPL_Init(RxCallBack);					// Init Wirless
  	
  	P2DIR &= ~(BIT3 + BIT2 + BIT1 + BIT0);	// P2.0, P2.1, P2.2, and P2.3 input
	P2REN |= BIT3 + BIT2 + BIT1 + BIT0;		// enable resistors on P2.0, P2.1, P2.2, and P2.3
	P2OUT |= BIT3 + BIT2 + BIT1 + BIT0;		// pullup resistors on P2.0, P2.1, P2.2, and P2.3
	zone = P2IN & 0x0F;						// read lower 4 bits of Port 2 to learn our zone
	P2REN &= ~(BIT3 + BIT2 + BIT1 + BIT0);	// turn off resistors to save power
  	
	P1DIR = ~(BIT6 + BIT5 + BIT4);         // P1.4, P1.5, P1.6 input 
	P1REN |= (BIT6 + BIT5 + BIT4);			// enable resistors on inputs
	P1OUT |= (BIT6 + BIT5 + BIT4);			// set inputs with pullup resistors
	P1IES = 0xFF;							// Port 1 interrups triggers on high to low transition
	P1IE = BIT6 + BIT5 + BIT4;				// P1.4, P1.5, P1.6 interrupt enable
	P1IFG = 0x00;							// clear port 1 interrupt flags
	__bis_SR_register(GIE);

	//P1OUT |= 1;								// set up stepper motor driver
  
	if(!(P1IN & BIT5))						// if the register is open...
	{													
		stop = 1;							// don't try to open it
		direction = OPEN;
	}
	
	TA1CCTL1 = CCIE;                        // CCR2 interrupt enabled
	TA1CCR1 = PERIOD;						// Load cap comp register with step period
  	
  	TA1CCR0 	= SLEEP_PERIOD;				// Load cap comp register with sleep period
  	TA1CCTL0 	= CCIE;                     // CCR0 interrupt enabled
  	TA1CTL 		= TASSEL_1 + MC_2;          // ACLK, continuous mode
  
 
///////////////////////////////////////////////////////////////////////////////////////// 
//___________________POSSIBLY NOT NEEDED DEPENDING ON WHAT BATTERY MONITOR NEEDS_________
/////////////////////////////////////////////////////////////////////////////////////////
   	REFCTL0   |= REFMSTR + REFVSEL_0 + REFON;    	// Enable internal 1.5V reference
  	ADC12CTL0  = ADC12SHT03 + ADC12SHT02 + ADC12ON;	// Set sample and hold time and turn on the ADC
  	ADC12CTL1  = ADC12SHP;
  	ADC12MCTL0 = ADC12INCH_10;						// Set channel 10 (temp. sensor) to memory bank 0
  	ADC12CTL0 |= ADC12ENC;							// Enable converstion	
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
}

void CTCLink()
{
	int i;
	int connected = FALSE;
	uint8_t size;
	
	for(i=0;i<5;i++)						// make max of 5 attempts to make quick CTC connection
	{
		BSP_TOGGLE_LED2();	// DEBUG
		
		SMPL_Send(SMPL_LINKID_USER_UUD, message, sizeof(message));	// send link message
		if(SMPL_Link(&linkID) == SMPL_SUCCESS)						// if successful break from loop
		{
			connected = TRUE;										// set connected flag
			break;
		}
		
		wait(QUICK_CONNECT_TIME);									// wait quick time for reconnect
	}
	
	if(!connected)													// no connection slow reconnect attempts
	{
		do
		{
			wait(LONG_CONNECT_TIME);								// wait longer since CTC is offline
			BSP_TOGGLE_LED2();	// DEBUG
			SMPL_Send(SMPL_LINKID_USER_UUD, message, sizeof(message));
		}
		while(SMPL_Link(&linkID) != SMPL_SUCCESS);					// loop while not connected
	}
	
	SMPL_Ioctl(IOCTL_OBJ_RADIO, IOCTL_ACT_RADIO_RXON, 0);			// turn radio on

	BSP_TURN_OFF_LED2();	// DEBUG
	
	message[TYPE]	   = RCR_IDENTIFY;								// send zone ID information
	message[ZONE_ID]   = zone;
	message[BATT_LIFE] = 26;
	SMPL_Send(linkID, message, sizeof(message));
	
	if(gotMessage)
	{
		SMPL_Receive(linkID, message, &size);						// receive confirmation and set new sleep time
		sleepTime = message[SLEEP_TIME];
	
		gotMessage = FALSE;											// reset message flag
	}
	else		// DEBUG blink led's if no ack message
	{
		BSP_TURN_ON_LED1();
		BSP_TURN_ON_LED2();
		wait(1);
		BSP_TOGGLE_LED1();
		BSP_TOGGLE_LED2();
		wait(1);
		BSP_TOGGLE_LED1();
		BSP_TOGGLE_LED2();
		wait(1);
		BSP_TOGGLE_LED1();
		BSP_TOGGLE_LED2();
		wait(1);
		BSP_TOGGLE_LED1();
		BSP_TOGGLE_LED2();
		wait(1);
		BSP_TOGGLE_LED1();
		BSP_TOGGLE_LED2();	
	}
	SMPL_Ioctl(IOCTL_OBJ_RADIO, IOCTL_ACT_RADIO_RXIDLE, 0);	// turn radio off		
}


void sendReq()
{
	uint8_t size;
	int8_t 	sendAttempts=0;
  
  	message[TYPE]		 = RCR_REQUEST;					// REQ Message
	message[BATT_LIFE]	 = 51;							// TODO put batt life into message
														// message[1] does not matter for RCR REQ message	 
 	 
 	sendAttempts = 0;
	gotMessage   = 0;
	while(gotMessage == 0)
	{	 	
		if(sendAttempts >= 5)							// only make 5 attempts or CTC error assumed
	 		RESET;										// CTC error force software reset
	
	 	sendAttempts++;									// count attempts
	 	
	 	SMPL_Send(linkID, message, sizeof(message));	// send message to CTC
	 	wait(2);										// wait 2 seconds before reatempt
	 	BSP_TOGGLE_LED2();	//DEBUG
	}
	
	SMPL_Receive(linkID, message, &size);				// receive confirmation and set new sleep time
	sleepTime    = message[SLEEP_TIME];
	newDirection = message[VENT_STATUS];				// get new vent status
	
	gotMessage = FALSE;									// reset message flag
		
	BSP_TURN_OFF_LED2();	//DEBUG
}


void updateVentPosition()
{
	if(newDirection != direction)						// if new position is differnent
	{
		direction = newDirection;						// update direction variable with new direction
		stop = FALSE;									// start motor
		TA1CCTL1 |= CCIE;
	}
}

void wait(int seconds)
{
	numSeconds = 0;				
	
	while(numSeconds < seconds)		// wait specified number of seconds
		SLEEP;
}


static uint8_t RxCallBack(linkID_t lid)
{
	if(lid == linkID)
		gotMessage = TRUE;				// set global flag
	return 0;
}


#pragma vector = TIMER1_A0_VECTOR
__interrupt void Timer1_A0(void)
{
	//P1OUT &= ~(0x0F);
	
	TA1CCR0 += SLEEP_PERIOD;		// set new interrupt to occur in 1 second
	
	P1OUT ^= BIT6;

	numSeconds++;					// incrment timer for wait() function
	LPM0_EXIT;						// exit low power mode for wait function to make decision
}


#pragma vector=TIMER1_A1_VECTOR
__interrupt void Timer1_A1 (void)
{
	if(stop)																	// if we shouldn't move...
	{
		P1OUT &= ~(0x0F);												// turn off all stepper coils
		TA1CCTL1 &= ~CCIE;
		return;
	}
	if(direction == CLOSE)											// if we need to open...
	{
	  motorState <<= 1;												// rotate one stop open
	  if(motorState > 8)
	  	motorState = 1;
	  P1OUT &= ~(0x0F);	  
	  P1OUT |= motorState;
	}
	else 
	{
		motorState >>= 1;												// otherwise we're closing
		if(motorState == 0)											// so close the motor one step
			motorState = 8;
	  P1OUT &= ~(0x0F);	  
	  P1OUT |= motorState;
	}
  TA1CCR1 += PERIOD;                        // Add Offset to CCR1
  TA1IV &= ~(0x02);
}

#pragma vector = PORT1_VECTOR
__interrupt void Port1(void)
{
	switch(P1IFG)
	{
		case BIT4:							// closed button has been hit
			if(direction == CLOSE)			// if we were in the closed state... (this is 'debouncing')
			{
				//direction = OPEN;			// switch to opening
				stop = TRUE;				// and stop
			}
			BSP_TOGGLE_LED1();
			break;
		case BIT5:							// open button has been hit
			if(direction == OPEN)			// if we were in the opened state...
			{
				//direction = CLOSE;		// switch to closing
				stop = TRUE;				// and stop
			}
			BSP_TOGGLE_LED2();
			break;
		/*case BIT6:						// toggle button has been hit
			stop = 0;						// so go
			break;*/
	}
	P1IFG = 0x00;							// clear the register flags
}
